using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace NeuroSpeech.Imap
{
	public class ImapResponseMessageHeader : BaseImapResponse
	{

		public MessageHeader[] Messages { get; private set; }

		protected override void ProcessLine(string line)
		{
			string lastLine = Lines.LastOrDefault();
			if (lastLine != null)
			{
				if (line.StartsWith("*"))
				{
					Lines.Add(line);
				}
				else {
					int lastIndex = Lines.Count - 1;
					Lines[lastIndex] = lastLine + "\r\n" + line;
				}
			}
			else
			{
				base.ProcessLine(line);
			}
		}

		#region public override void  Process(ImapClient client)
		public override void Process(ImapClient client)
		{
			base.Process(client);

			List<MessageHeader> list = new List<MessageHeader>();

			foreach (var item in Lines)
			{
				var tree = Parse(item);

				MessageHeader m = new MessageHeader();
				m.Id = ulong.Parse(tree.GetChild(1).Text);

				if (m.Id == 713)
					Debugger.Break();

				tree = tree.GetChild(3);

				for (int i = 0; i < tree.ChildCount; i++)
				{
					var child = tree.GetChild(i);
					string type = child.Text.ToLower();
					switch (type)
					{
						case "body":
						case "bodystructure":
							{
								m.MimePart = ParseMimePart(child);
							}
							break;
						case "flags":
							{
								m.Flags = ParseFlags(child);
							}
							break;
						case "envelope":
							{
								ParseEnvelope(m, child);
							}
							break;
						case "rfc822.size":
							{
								string size = child.GetChild(0).Text;
								m.Size = int.Parse(size);
							}
							break;
						case "uid":
							{
								string uid = child.GetChild(0).Text;
								m.UID = ulong.Parse(uid);
							}
							break;
						case "internaldate":
							{
								string date = child.GetChild(0).Text;
								try
								{
									m.InternalDate = DateTime.Parse(date);
								}
								catch (Exception ex)
								{
									Trace.WriteLine(" Parsing of " + date + " failed \r\n" + ex.ToString());
								}
							}
							break;
						default:
							Trace.WriteLine("No parsing for " + type);
							break;
					}
				}

				//string date = tree.GetChild(1).GetChild(0).Text;
				//try
				//{
				//    m.InternalDate = DateTime.Parse(date);
				//}
				//catch(Exception ex) {
				//    Trace.WriteLine(" Parsing of " + date + " failed \r\n" + ex.ToString());
				//}

				//var s = tree.GetChild(2).GetChild(0).Text;

				//m.Size = long.Parse(s);

				//ParseEnvelope(m, tree.GetChild(3));

				//m.MimePart = ParseMimePart(tree.GetChild(4));

				list.Add(m);
			}

			Messages = list.ToArray();
		}

		#region private string[] ParseFlags(Antlr.Runtime.Tree.ITree child)
		private string[] ParseFlags(Antlr.Runtime.Tree.ITree tree)
		{
			List<string> list = new List<string>();
			for (int i = 0; i < tree.ChildCount; i++)
			{
				var child = tree.GetChild(i);
				list.Add(child.Text);
			}
			return list.ToArray();
		}
		#endregion


		#region private MimePart ParseMimePart(Antlr.Runtime.Tree.ITree iTree)
		private ImapMimePart ParseMimePart(Antlr.Runtime.Tree.ITree tree, string prefix = "")
		{
			if (tree.ChildCount == 0)
				return null;

			ImapMimePart m = new ImapMimePart();
			m.PartIndex = prefix;

			var first = tree.GetChild(0);
			if (first.Text != "(")
			{
				m.ContentType = tree.GetChild(0).Text + "/" + tree.GetChild(1).Text;
				var cs = tree.GetChild(2);
				if (cs.ChildCount > 0)
				{
					m.CharSet = cs.GetChild(0).Text;
					m.CodePage = cs.GetChild(1).Text;
				}
				m.ContentID = tree.GetChild(3).Text;
				m.FileName = tree.GetChild(4).Text;
				m.Encoding = tree.GetChild(5).Text;
				m.Size = int.Parse(tree.GetChild(6).Text);
			}
			else
			{
				List<ImapMimePart> parts = new List<ImapMimePart>();
				int i = 0;
				for (i = 0; i < tree.ChildCount - 1; i++)
				{
					var child = tree.GetChild(i);
					if (child.Text != "(")
						break;
					string p = m.PartIndex;
					if (string.IsNullOrWhiteSpace(p))
					{
						p = (i + 1).ToString();
					}
					else
					{
						p += "." + (i + 1).ToString();
					}
					ImapMimePart cp = ParseMimePart(child, p);
					if (cp != null)
					{
						parts.Add(cp);
					}
				}
				var c = tree.GetChild(i).Text;
				m.Relation = c;
				m.ChildParts = parts.ToArray();
			}
			return m;
		}
		#endregion


		#region private void ParseEnvelope(MessageInfo m,Antlr.Runtime.Tree.ITree iTree)
		private void ParseEnvelope(MessageHeader m, Antlr.Runtime.Tree.ITree tree)
		{
			string date = tree.GetChild(0).Text.Trim('"');
			m.MessageDate = date;

			m.Subject = tree.GetChild(1).Text;

			m.From = ParseAddresses(tree.GetChild(2));
			m.Sender = ParseAddresses(tree.GetChild(3));
			m.ReplyTo = ParseAddresses(tree.GetChild(4));
			m.To = ParseAddresses(tree.GetChild(5));
			m.Cc = ParseAddresses(tree.GetChild(6));
			m.Bcc = ParseAddresses(tree.GetChild(7));
			m.InReplyTo = ParseAddresses(tree.GetChild(8));
			m.MessageID = tree.GetChild(9).Text;
		}

		#region private AddressInfo[] ParseAddresses(Antlr.Runtime.Tree.ITree iTree)
		private AddressInfo[] ParseAddresses(Antlr.Runtime.Tree.ITree tree)
		{
			List<AddressInfo> list = new List<AddressInfo>();
			for (int i = 0; i < tree.ChildCount; i++)
			{
				AddressInfo ai = new AddressInfo { };
				var child = tree.GetChild(i);

				ai.PersonalName = child.GetChild(0).Text;
				ai.SourceRoute = child.GetChild(1).Text;
				ai.Mailbox = child.GetChild(2).Text;
				ai.Domain = child.GetChild(3).Text;
				list.Add(ai);
			}
			return list.ToArray();
		}
		#endregion

		#endregion

		#endregion


	}
}
